home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 / Ham Radio 2000.iso / ham2000 / satellit / pfholes / pfholes.c < prev    next >
C/C++ Source or Header  |  1991-08-25  |  7KB  |  279 lines

  1. /* Usage: pfholes file1.hol ... fileN.hol
  2.  
  3. Summarizes the amount of data received and missing in broadcast files.
  4.  
  5. Written 8-91 by James Dugal, N5KNX
  6. Ver 2, 8-91 jpd (added scan of PG.DIR to obtain file lengths when possible)
  7.         -- thanks to pe1chl for code borrowed from pfh.c
  8.  
  9. Compile by:  tcc -O -G -Z -a pfholes.c wildargs.obj
  10. */
  11.  
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <errno.h>
  15. #include <sys\types.h>
  16. #include <dir.h>
  17.  
  18. /* The SHORT_DIR structure describes the fixed length directory
  19. ** entry for the PG.DIR file, version 910207r. The strings (title, source, etc)
  20. ** are truncated to fit the structure, if necessary.
  21. ** NOTE: types are defined as for the Intel 80x86 architecture; be careful!
  22. */
  23. struct SHORT_DIR{
  24.   unsigned long fnumber;
  25.   unsigned long fsize;
  26.   unsigned char title[40];
  27.   unsigned char source[20];
  28.   unsigned char dest[20];
  29.   unsigned char keywords[20];
  30.   time_t ultime;
  31.   unsigned int dlcount;
  32. };
  33. #define SHORT_DIR_SIZE 114
  34.  
  35. struct dir_entry
  36.     {
  37.     struct dir_entry *next,*prev;
  38.     unsigned long file_id;
  39.     unsigned long fsize;
  40.     } *entry_list=NULL,*new,*find;
  41.  
  42. char currpgdir[MAXPATH] = "";
  43. char nomem[] = "Out of memory!";
  44. char fmterr[] = "%s: internal format error";
  45.  
  46.  
  47. char *trim(const char *s)    /* remove filename's extension & directory parts */
  48. {
  49.     char *r,*q;
  50.     static char res[256];    /* We can't modify the input string! */
  51.  
  52.     strcpy(res, s);
  53.     if ((r=(char *)strrchr(res,'\\')) == NULL) r=res;
  54.     else *r++='\0';
  55.     if ((q=(char *)strchr(r, '.')) != NULL) *q='\0';
  56.     return(r);
  57. }
  58.  
  59.  
  60. /* Convert a little-endian (ie, Intel) binary value into an unsigned long */
  61. unsigned long convert_num(cp, len)
  62. unsigned char *cp;
  63. int len;
  64. {
  65.     unsigned long val;
  66.     int i;
  67.  
  68.     val = 0L;
  69.  
  70.     for (i = 0; i < len; i++)
  71.         val |= (unsigned long) *cp++ << (8 * i);
  72.  
  73.     return (val);
  74. }
  75.  
  76.  
  77. int readpgdir (filename)
  78.     char *filename;    /* eg, "PG.DIR" */
  79.  
  80. {
  81.     FILE *dir;
  82.     unsigned long file_id;
  83.     char data[SHORT_DIR_SIZE+1];
  84.     
  85.  
  86.     if ((dir = fopen(filename,"rb")) == NULL)    /* open the existing dir file */
  87.     {
  88. #ifdef DEBUG
  89.     perror(filename);
  90. #endif
  91.     return 2;
  92.     }
  93.  
  94.     /* put dummy item in the list */
  95.  
  96.     if ((entry_list = (struct dir_entry *) malloc(sizeof(struct dir_entry))) == NULL)
  97.     {
  98.     fprintf(stderr,nomem);
  99.     fclose(dir);
  100.     return 5;
  101.     }
  102.  
  103.     entry_list->next = entry_list->prev = NULL;
  104.     entry_list->file_id = (unsigned long)0xffffffffL;
  105.  
  106.     for (;;)    /* read all items from directory */
  107.     {
  108.     /* read dir entry */
  109.  
  110.         if (fread(data,1,SHORT_DIR_SIZE,dir) != SHORT_DIR_SIZE)    /* read data */
  111.         break;
  112.  
  113.     file_id = convert_num (&data[0], 4);        /* file number */
  114.  
  115.     if (file_id == 0)
  116.         continue;
  117.  
  118.     /* save this dir entry in a list item */
  119.  
  120.     if ((new = (struct dir_entry *) malloc(sizeof(struct dir_entry))) == NULL)
  121.     {
  122.         fprintf(stderr,nomem);
  123.         fclose(dir);
  124.         return 5;
  125.     }
  126.  
  127.     new->next = new->prev = NULL;
  128.     new->file_id = file_id;
  129.     new->fsize = convert_num (&data[4], 4);        /* file size */
  130.  
  131.  
  132.     /* scan the list to find it's place (insertion sort) */
  133.  
  134.     for (find = entry_list; find != NULL; find = find->next)
  135.         if (find->file_id > file_id)
  136.         {
  137.         /* has to be inserted before this one */
  138.  
  139.         if ((new->prev = find->prev) != NULL)
  140.             find->prev->next = new;
  141.         else
  142.             entry_list = new;
  143.  
  144.         new->next = find;
  145.         find->prev = new;
  146.         break;
  147.         }
  148.     }
  149.  
  150.     /* Finished with pg.dir file scan; we should be at EOF, else is damaged */
  151.     if (!feof(dir))
  152.     {
  153.     fprintf(stderr,fmterr,filename);
  154.     fclose(dir);
  155.     return 3;
  156.     }
  157.  
  158.     fclose(dir);
  159. #ifdef DEBUG
  160.     for (find=entry_list; find != NULL; find=find->next)
  161.     {
  162.     printf("%lu,%lu\n", find->file_id, find -> fsize);
  163.     }
  164. #endif
  165.     return 0;
  166. }
  167.  
  168. unsigned long
  169. getlen(unsigned long fileid) {
  170.     for (find=entry_list; find != NULL; find=find->next)
  171.     {
  172.     if (find->file_id == fileid) return(find -> fsize);
  173.     else if (find->file_id > fileid) return(0);    /* unknown */
  174.     }
  175.     return(0);    /* unknown */
  176. }
  177.  
  178. void
  179. free_list(void)
  180. {
  181.     for (find=entry_list; find != NULL; )
  182.     {    new = find -> next;
  183.         free (find);
  184.         find = new;
  185.     }
  186.     entry_list = NULL;
  187. }
  188.  
  189. void
  190. loadpgdir(const char *holpath)    /* Given path to .HOL file, load corresponding PG.DIR */
  191. {
  192.     char path[MAXPATH], drive[MAXDRIVE], dir[MAXDIR];
  193.  
  194.     (void)fnsplit(holpath, drive, dir, NULL, NULL);
  195.     fnmerge(path, drive, dir, "PG", ".DIR");
  196.     if (strcmp(path, currpgdir) == 0) return; /* Same PG.DIR as last time */
  197.     if (currpgdir[0]) free_list();    /* different PG.DIR, free mem holding previous PG.DIR */
  198.     strcpy(currpgdir, path);    /* make new one current */
  199.     if (readpgdir(currpgdir)) return;    /* error, can't read PG.DIR */
  200.  
  201. }
  202.  
  203.  
  204. void main(int argc, char *argv[])
  205. {
  206.  
  207.     FILE *f;
  208.     int i,h;
  209.     unsigned hcnt, hrcnt, linecnt;
  210.     unsigned long from, to, prev_to, prev_need, got, need, maxlen, filenum;
  211.     char me[MAXFILE];
  212.     char buf[256], *filenm;
  213.  
  214.  
  215.     strcpy(me, trim(argv[0]));
  216.     if (argc == 1) {
  217.         printf("Usage: %s file1.hol ... fileN.hol\n"
  218.             "\tsummarizes amount of bytes received and missing from bcst files.\n",
  219.             me);
  220.         exit(1);
  221.     }
  222.             
  223.     printf("FILE\t\tSIZE\tHOLES\tHAVE\tNEED\n");
  224.     for (i=1; i<argc; i++) {
  225.         filenm=trim(argv[i]);
  226.         (void)sscanf(filenm,"%lX", &filenum);
  227.         printf("\n%s\t\t", filenm);
  228.  
  229.         if ((f=fopen(argv[i], "r")) == NULL) {
  230.             perror(me);
  231.             continue;
  232.         }
  233.         loadpgdir(argv[i]);    /* build list of PG.DIR's interesting contents */
  234.  
  235.         linecnt=0;
  236.         if (fgets(buf, sizeof(buf), f) == NULL) goto bad_fmt;
  237.         linecnt++;
  238.         if (sscanf(buf, "%u pfh header received\n", &hrcnt) != 1) goto bad_fmt;
  239.         if (fgets(buf, sizeof(buf), f) == NULL) goto bad_fmt;
  240.         linecnt++;
  241.         if (sscanf(buf, "%lu pfh file length\n", &maxlen) != 1) goto bad_fmt;
  242.         if (maxlen == 0L) maxlen = getlen(filenum);    /* use value from PG.DIR */
  243.         if (fgets(buf, sizeof(buf), f) == NULL) goto bad_fmt;
  244.         linecnt++;
  245.         if (sscanf(buf, "%u holes\n", &hcnt) != 1) {
  246. bad_fmt:        if (errno) perror(me);
  247.             fprintf(stderr, "%s: Data in unexpected format near line %u.", argv[i], linecnt);
  248.             fclose(f);
  249.             continue;
  250.         }
  251.  
  252.         got = need = prev_to = 0L;
  253.         for (h=0; h<hcnt; h++) {
  254.             if (fgets(buf, sizeof(buf), f) == NULL) goto bad_fmt;
  255.             linecnt++;
  256.             if (sscanf(buf, "%lu, %lu\n", &from, &to) != 2) goto bad_fmt;
  257.  
  258.             if (from) {
  259.                 got += from - prev_to -1;
  260.                 if (!prev_to) got++;
  261.             }
  262.  
  263.             if (h == (hcnt-1) && maxlen) to = min(maxlen-1, to);    /* correct last hole's length */
  264.             prev_need = need;
  265.             need += to - from + 1;
  266.             prev_to= to;
  267.         }
  268.  
  269.         if (maxlen == 0L)
  270.             printf ("?\t%u\t%lu\t>%lu", hcnt, got, prev_need);
  271.         else printf ("%lu\t%u\t%lu\t%lu", maxlen, hcnt, got, need);
  272.         fclose(f);
  273.     }
  274.     printf("\n");
  275. }
  276.  
  277.  
  278.  
  279.